#include "Mesh.h"


#include <ezlogger_headers.hpp>


namespace Crows3D
{
   Mesh::Mesh(void)
   {
      EZLOGGERSTREAM << "Mesh Constructor" << std::endl;

      vb = NULL;
      ib = NULL;
   }

   Mesh::~Mesh(void)
   {
      EZLOGGERSTREAM << "Mesh Destructor" << std::endl;

      if (vb)
      {
         vb->Release();
         vb = NULL;
      }

      if (ib)
      {
         ib->Release();
         ib = NULL;
      }
   }

   bool Mesh::Initialize(Crows3D::Device *dev, unsigned long numVerts, VertexPositionTextureNormal verts[], 
                                               unsigned long numIndices, DWORD indices[])
   {
      EZLOGGERSTREAM << "Creating mesh from vertex/index arrays. Num Verts: " << numVerts << ", Num Indices: " << numIndices << std::endl;

      D3D11_BUFFER_DESC bd;
      D3D11_SUBRESOURCE_DATA initData;

      // Set up our vb parameters
      memset(&bd, 0, sizeof(bd));
      bd.Usage = D3D11_USAGE_DEFAULT;                                // write access access by CPU and GPU
      bd.ByteWidth = sizeof(VertexPositionTextureNormal) * numVerts; // size is the VERTEX struct * 3
      bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;                       // use as a vertex buffer
      bd.CPUAccessFlags = 0;                                         // do NOT allow CPU to write in buffer

      // Fill the buffer with some default data
      memset(&initData, 0, sizeof(D3D11_SUBRESOURCE_DATA));
      initData.pSysMem = verts;
	   initData.SysMemPitch = 0;
	   initData.SysMemSlicePitch = 0;

      if (FAILED(dev->GetDevice()->CreateBuffer(&bd, &initData, &vb))) // create the buffer
      {
         EZLOGGERSTREAM << "ERROR: Failed to create vertex buffer for mesh" << std::endl;

         return false;
      }
      

      // Set up our ib parameters
      memset(&bd, 0, sizeof(bd));
      bd.Usage = D3D11_USAGE_DEFAULT;                 // write access access by CPU and GPU
      bd.ByteWidth = sizeof(DWORD) * numIndices;      // size is the VERTEX struct * 3
      bd.BindFlags = D3D11_BIND_INDEX_BUFFER;         // use as a index buffer
      bd.CPUAccessFlags = 0;                          // do NOT allow CPU to write in buffer

      memset(&initData, 0, sizeof(D3D11_SUBRESOURCE_DATA));
      initData.pSysMem = indices;
	   initData.SysMemPitch = 0;
	   initData.SysMemSlicePitch = 0;

      if (FAILED(dev->GetDevice()->CreateBuffer(&bd, &initData, &ib))) // create the buffer
      {
         EZLOGGERSTREAM << "ERROR: Failed to create index buffer for mesh" << std::endl;
         return false;
      }


      nIndices = numIndices;


      return true;
   }

   bool Mesh::InitializeCube(Crows3D::Device *dev)
   {  
      VertexPositionTextureNormal verts[] =
      {
         // top (yellow)
         { D3DXVECTOR4(-1.0f,  1.0f,  1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( 0.0f, -1.0f, 0.0f)},
         { D3DXVECTOR4( 1.0f,  1.0f, -1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( 0.0f, -1.0f, 0.0f)},
         { D3DXVECTOR4(-1.0f,  1.0f, -1.0f, 1.0f), D3DXVECTOR2( 0.0f, 1.0f), D3DXVECTOR3( 0.0f, -1.0f, 0.0f)},
         { D3DXVECTOR4( 1.0f,  1.0f,  1.0f, 1.0f), D3DXVECTOR2( 1.0f, 0.0f), D3DXVECTOR3( 0.0f, -1.0f, 0.0f)},
         { D3DXVECTOR4( 1.0f,  1.0f, -1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( 0.0f, -1.0f, 0.0f)},
         { D3DXVECTOR4(-1.0f,  1.0f,  1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( 0.0f, -1.0f, 0.0f)},

         // back
         { D3DXVECTOR4(-1.0f,  1.0f, -1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( 0.0f, 0.0f, -1.0f)},
         { D3DXVECTOR4( 1.0f, -1.0f, -1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( 0.0f, 0.0f, -1.0f)},
         { D3DXVECTOR4(-1.0f, -1.0f, -1.0f, 1.0f), D3DXVECTOR2( 0.0f, 1.0f), D3DXVECTOR3( 0.0f, 0.0f, -1.0f)},
         { D3DXVECTOR4( 1.0f,  1.0f, -1.0f, 1.0f), D3DXVECTOR2( 1.0f, 0.0f), D3DXVECTOR3( 0.0f, 0.0f, -1.0f)},
         { D3DXVECTOR4( 1.0f, -1.0f, -1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( 0.0f, 0.0f, -1.0f)},
         { D3DXVECTOR4(-1.0f,  1.0f, -1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( 0.0f, 0.0f, -1.0f)},

         // right
         { D3DXVECTOR4(-1.0f,  1.0f,  1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( -1.0f, 0.0f, 0.0f)},
         { D3DXVECTOR4(-1.0f, -1.0f, -1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( -1.0f, 0.0f, 0.0f)},
         { D3DXVECTOR4(-1.0f, -1.0f,  1.0f, 1.0f), D3DXVECTOR2( 0.0f, 1.0f), D3DXVECTOR3( -1.0f, 0.0f, 0.0f)},
         { D3DXVECTOR4(-1.0f,  1.0f, -1.0f, 1.0f), D3DXVECTOR2( 1.0f, 0.0f), D3DXVECTOR3( -1.0f, 0.0f, 0.0f)},
         { D3DXVECTOR4(-1.0f, -1.0f, -1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( -1.0f, 0.0f, 0.0f)},
         { D3DXVECTOR4(-1.0f,  1.0f,  1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( -1.0f, 0.0f, 0.0f)},

         // left
         { D3DXVECTOR4( 1.0f,  1.0f, -1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( 1.0f, 0.0f, 0.0f)},
         { D3DXVECTOR4( 1.0f, -1.0f,  1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( 1.0f, 0.0f, 0.0f)},
         { D3DXVECTOR4( 1.0f, -1.0f, -1.0f, 1.0f), D3DXVECTOR2( 0.0f, 1.0f), D3DXVECTOR3( 1.0f, 0.0f, 0.0f)},
         { D3DXVECTOR4( 1.0f,  1.0f,  1.0f, 1.0f), D3DXVECTOR2( 1.0f, 0.0f), D3DXVECTOR3( 1.0f, 0.0f, 0.0f)},
         { D3DXVECTOR4( 1.0f, -1.0f,  1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( 1.0f, 0.0f, 0.0f)},
         { D3DXVECTOR4( 1.0f,  1.0f, -1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( 1.0f, 0.0f, 0.0f)},

         // front
         { D3DXVECTOR4( 1.0f,  1.0f,  1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( 0.0f, 0.0f, 1.0f)},
         { D3DXVECTOR4(-1.0f, -1.0f,  1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( 0.0f, 0.0f, 1.0f)},
         { D3DXVECTOR4( 1.0f, -1.0f,  1.0f, 1.0f), D3DXVECTOR2( 0.0f, 1.0f), D3DXVECTOR3( 0.0f, 0.0f, 1.0f)},
         { D3DXVECTOR4(-1.0f,  1.0f,  1.0f, 1.0f), D3DXVECTOR2( 1.0f, 0.0f), D3DXVECTOR3( 0.0f, 0.0f, 1.0f)},
         { D3DXVECTOR4(-1.0f, -1.0f,  1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( 0.0f, 0.0f, 1.0f)},
         { D3DXVECTOR4( 1.0f,  1.0f,  1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( 0.0f, 0.0f, 1.0f)},

         // bottom
         { D3DXVECTOR4( 1.0f, -1.0f,  1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( 0.0f, 1.0f, 0.0f)},
         { D3DXVECTOR4(-1.0f, -1.0f, -1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( 0.0f, 1.0f, 0.0f)},
         { D3DXVECTOR4( 1.0f, -1.0f, -1.0f, 1.0f), D3DXVECTOR2( 0.0f, 1.0f), D3DXVECTOR3( 0.0f, 1.0f, 0.0f)},  
         { D3DXVECTOR4(-1.0f, -1.0f,  1.0f, 1.0f), D3DXVECTOR2( 1.0f, 0.0f), D3DXVECTOR3( 0.0f, 1.0f, 0.0f)},
         { D3DXVECTOR4(-1.0f, -1.0f, -1.0f, 1.0f), D3DXVECTOR2( 1.0f, 1.0f), D3DXVECTOR3( 0.0f, 1.0f, 0.0f)},
         { D3DXVECTOR4( 1.0f, -1.0f,  1.0f, 1.0f), D3DXVECTOR2( 0.0f, 0.0f), D3DXVECTOR3( 0.0f, 1.0f, 0.0f)},
      };

      DWORD indices[] = 
      {
          0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
         10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
         20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
         30, 31, 32, 33, 34, 35,
      };

      
      return this->Initialize(dev, 36, verts, 36, indices);
   }

   void Mesh::Commit(Crows3D::Device *dev)
   {
      UINT stride = sizeof(VertexPositionTextureNormal);
      UINT offset = 0;


      // Make sure the buffers were created
      if ((!vb) || (!ib))
      {
         return;
      }


      

      // Set the vertex and index buffer
      dev->GetDeviceContext()->IASetVertexBuffers(0, 1, &vb, &stride, &offset);
      dev->GetDeviceContext()->IASetIndexBuffer(ib, DXGI_FORMAT_R32_UINT, 0);

      // Tell the device it'll be a list of triangles
      dev->GetDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

      
   }

   void Mesh::Render(Crows3D::Device *dev)
   {
      dev->GetDeviceContext()->DrawIndexed(nIndices, 0, 0);
   }
}